package com.hmall.search.web;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSON;
import com.hmall.common.dto.PageDTO;
import com.hmall.search.pojo.ItemDoc;
import com.hmall.search.pojo.RequestParams;
import com.hmall.search.service.SearchService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;

import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


 import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


@RestController
@RequestMapping("search")
public class SearchController {
    @Autowired
    private RestHighLevelClient client;

    @Autowired
    private SearchService searchService;

    @PostMapping("/list")
    public PageDTO<ItemDoc> pagingQuery(@RequestBody RequestParams requestParams) throws IOException {
        SearchRequest request = new SearchRequest("item");
        buildBasicQuery(request,requestParams);
        Integer page = requestParams.getPage();
        Integer size = requestParams.getSize();
//        request.source().query(QueryBuilders.matchAllQuery());
        String sortBy = requestParams.getSortBy();
        //排序
        if ("sold".equals(sortBy)) {
            request.source().sort(sortBy, SortOrder.DESC);
        } else if ("price".equals(sortBy)) {
            request.source().sort(sortBy, SortOrder.ASC);
        }
        //分页
        request.source().from((page - 1) * size).size(size);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits search = response.getHits();
        long total = search.getTotalHits().value;
        List<ItemDoc> itemDocs = handleResponse(response);
        return new PageDTO<>(total,itemDocs) ;
    }

    private List<ItemDoc> handleResponse(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        // 4.1.总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("总条数：" + total);
        // 4.2.获取文档数组
        SearchHit[] hits = searchHits.getHits();
        // 4.3.遍历
        ArrayList<ItemDoc> list = new ArrayList<>(hits.length);
        for (SearchHit hit : hits) {
            // 4.4.获取source
            String json = hit.getSourceAsString();
            // 4.5.反序列化，非高亮的
            ItemDoc itemDoc = JSON.parseObject(json, ItemDoc.class);
            // 4.6.处理高亮结果
            // 1)获取高亮map
            Map<String, HighlightField> map = hit.getHighlightFields();
            // 2）根据字段名，获取高亮结果
            // 3）获取高亮结果字符串数组中的第1个元素
            if (map != null && map.size() > 0){{
            HighlightField highlightField = map.get("name");
            String hName = highlightField.getFragments()[0].toString();
            itemDoc.setName(hName);
            }}
            // 4）把高亮结果放到ItemDoc中
            list.add(itemDoc);
        }
        return list;
    }


    @PostMapping("/filters")
    public Map<String,List<String>> getFilters(@RequestBody RequestParams requestParams) throws IOException {
        return  searchService.getFilters(requestParams);
    }



    private void buildBasicQuery(SearchRequest request, RequestParams params) {
        // 1.创建布尔查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // 1.1. key
        String key = params.getKey();
        if (StringUtils.isNotBlank(key)) {
            // 非空
            boolQuery.must(QueryBuilders.matchQuery("all", key));
        } else {
            // 空
            boolQuery.must(QueryBuilders.matchAllQuery());
        }
        // 1.2. brand
        String brand = params.getBrand();
        if (StringUtils.isNotBlank(brand)) {
            boolQuery.filter(QueryBuilders.termQuery("brand", brand));
        }
        // 1.3. category
        String category = params.getCategory();
        if (StringUtils.isNotBlank(category)) {
            boolQuery.filter(QueryBuilders.termQuery("category", category));
        }
        // 1.4. price
        Long minPrice = params.getMinPrice();
        Long maxPrice = params.getMaxPrice();
        if (minPrice != null && maxPrice != null) {
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(minPrice * 100).lte(maxPrice * 100));
        }

        // 2.放入request
        FunctionScoreQueryBuilder queryBuilder = QueryBuilders.functionScoreQuery(
                boolQuery,
                new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                QueryBuilders.termQuery("isAD", true),
                                ScoreFunctionBuilders.weightFactorFunction(100)
                        )
                }
        );
        request.source().query(queryBuilder);
    }



}
